#!/usr/bin/env python
# -*- coding: UTF-8 -*-

'''GUI for http://en.wikipedia.org/wiki/Cellular_automaton#Elementary_cellular_automata'''

import sys
import random

from cellular_automata.elementary import ElementaryCellularAutomata

import pygame
from pygame.locals import *

pygame.init()

RULE = 150

FONTSIZE = 64
FONTNAME = 'Terminal'
FONT_OBJ = pygame.font.SysFont(FONTNAME, FONTSIZE)

TILE_SIZE = (16, 16)
CELLS_PER_ROW = 69
VERTICAL_ROWS = 25
STARTING_ROW = '1'

COLOR_DEAD = (255, 255, 255)
COLOR_BORDER = (100, 100, 100)

WINDOW_WIDTH = TILE_SIZE[0] * CELLS_PER_ROW
WINDOW_HEIGHT = TILE_SIZE[1] * VERTICAL_ROWS

DEAD_IMAGE = pygame.Surface(TILE_SIZE)
DEAD_IMAGE.fill(COLOR_DEAD)

DELAY = 80


def draw_to_surface(elementary, surface):
    tile_width, tile_height = TILE_SIZE

    rows = elementary.rows
    row = rows[-1]
    surface.scroll(0, -tile_height)

    # Get a random color that isn't too close to black
    color = (0, 0, 0)
    while color[0] + color[1] + color[2] < 50:
        color = (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))

    alive_image = pygame.Surface(TILE_SIZE)
    alive_image.fill(color)
    pygame.draw.rect(alive_image, COLOR_BORDER, alive_image.get_rect(), 1)

    dead_image = DEAD_IMAGE

    # Always draw at the bottom
    y_mod = VERTICAL_ROWS - 1
    for x_mod, char in enumerate(row):
        if char == '1':
            position = x_mod * tile_width, y_mod * tile_height

            surface.blit(alive_image, position)
        else:
            position = x_mod * tile_width, y_mod * tile_height

            surface.blit(dead_image, position)

    # Why keep all previous iterations around? Just keep the latest so we
    # can calculate the next generation
    if len(rows) != 1:
        rows.pop(len(rows) - 2)

    pygame.display.update()


def get_text_obj_and_pos(text):
    textObj = FONT_OBJ.render(str(text), True, (255, 0, 0))
    textPos = (surface.get_rect().width - textObj.get_rect().width,
               surface.get_rect().height - textObj.get_rect().height)

    return textObj, textPos

if __name__ == '__main__':
    surface = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))
    surface.convert()
    surface.fill(COLOR_DEAD)

    cell_surface = surface.copy()

    pygame.display.update()
    pygame.display.set_caption('Elementary Cellular Automata')

    bPause = True
    ca = ElementaryCellularAutomata(RULE, STARTING_ROW, CELLS_PER_ROW)
    draw_to_surface(ca, cell_surface)

    textObj, textPos = get_text_obj_and_pos(RULE)

    def quit_everything():
        pygame.quit()
        sys.exit()

    while True:
        for event in pygame.event.get():
            e_type = event.type

            if e_type == QUIT:
                quit_everything()
            elif e_type == KEYDOWN:
                key = event.key

                if key == K_SPACE:
                    bPause = not bPause
                elif key == K_3 and bPause:
                    ca.game_loop()
                    draw_to_surface(ca, cell_surface)
                elif key == K_UP:
                    DELAY += 10
                    print('Changed delay to: {0}'.format(DELAY))
                elif key == K_DOWN:
                    if DELAY > 0:
                        DELAY -= 10
                        print('Changed delay to: {0}'.format(DELAY))
                elif key == K_LEFT:
                    if RULE > 0:
                        RULE -= 1
                        starting_row = ca.rows[-1]
                        ca = ElementaryCellularAutomata(RULE, starting_row, CELLS_PER_ROW)
                        textObj, textPos = get_text_obj_and_pos(RULE)
                elif key == K_RIGHT:
                    if RULE < 256:
                        RULE += 1
                        starting_row = ca.rows[-1]
                        ca = ElementaryCellularAutomata(RULE, starting_row, CELLS_PER_ROW)
                        textObj, textPos = get_text_obj_and_pos(RULE)
                elif key == K_ESCAPE:
                    quit_everything()

        if not bPause:
            ca.game_loop()
            draw_to_surface(ca, cell_surface)

        surface.blit(cell_surface, (0, 0))
        surface.blit(textObj, textPos)
        pygame.display.update()

        pygame.time.delay(DELAY)
